/*
 * @(#)BlindSearch.java        1.0 2000/06/26
 *
 * This file is part of Xfuzzy 3.0, a design environment for fuzzy logic
 * based systems.
 *
 * (c) 2000 IMSE-CNM. The authors may be contacted by the email address:
 *                    xfuzzy-team@imse.cnm.es
 *
 * Xfuzzy is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
 * Xfuzzy is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 */

package xfuzzy.xfsl.model.algorithm;

import xfuzzy.xfsl.model.*;
import xfuzzy.lang.*;
import java.util.Random;
import xfuzzy.xfds.XfdsDataSet;

/**
 * Algoritmo de b�squeda ciega
 * 
 * @author Francisco Jos� Moreno Velo
 *
 */
public class BlindSearch extends XfslAlgorithm {

	//----------------------------------------------------------------------------//
	//                            MIEMBROS PRIVADOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Tama�o de las perturbaciones
	 */
	private double pert;
	
	/**
	 * �ltima evaluaci�n
	 */
	private XfslEvaluation last;
	
	/**
	 * Generador de n�meros aleatorios
	 */
	private Random random;

	//----------------------------------------------------------------------------//
	//                                CONSTRUCTOR                                 //
	//----------------------------------------------------------------------------//

	/**
	 * 
	 */
	public BlindSearch() {
		this.pert = 1;
		this.random = new Random();
	}

	//----------------------------------------------------------------------------//
	//                             M�TODOS P�BLICOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Devuelve el c�digo de identificaci�n del algoritmo
	 */
	public int getCode() {
		return BLIND;
	}

	/**
	 * Actualiza los par�metros de configuraci�n del algoritmo
	 */
	public void setParameters(double[] param) throws XflException {
		if(param.length != 1) throw new XflException(26);
		pert = test(param[0], POSITIVE);
	}

	/**
	 * Obtiene los par�metros de configuraci�n del algoritmo
	 */
	public XfslAlgorithmParam[] getParams() {
		XfslAlgorithmParam[] pp = new XfslAlgorithmParam[1];
		pp[0] = new XfslAlgorithmParam(pert, 1, POSITIVE, "Perturbation");
		return pp;
	}

	/**
	 * Ejecuta una iteraci�n del algoritmo
	 */
	public XfslEvaluation iteration(Specification spec, XfdsDataSet pattern,
			XfslErrorFunction ef) throws XflException {
		if(init) { init = false; last = ef.evaluate(spec,pattern,1.0); } 

		Parameter[] param = spec.getAdjustable();
		double[] p = new double[param.length];
		for(int i=0; i<param.length; i++) p[i] = param[i].value;

		XfslEvaluation eval=null;
		boolean found=false;
		for(int trial=0; trial<20; trial++) {
			perturb(spec);
			eval = ef.evaluate(spec,pattern,last.error);
			if(eval.error < last.error) { found=true; break; }
			for(int i=0; i<param.length; i++) param[i].value = p[i];
		}

		if(!found) {
			eval = new XfslEvaluation();
			eval.error = last.error;
			eval.rmse = last.rmse;
			eval.mxae = last.mxae;
			eval.var = 0;
		}

		last = eval;
		return eval;
	}

	//----------------------------------------------------------------------------//
	//                             M�TODOS PRIVADOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Realiza una perturbaci�n del sistema
	 */
	private void perturb(Specification spec) {
		Type[] type = spec.getTypes();
		for(int i=0; i<type.length; i++) {
			if(!type[i].isAdjustable()) continue;

			Family fam[] = type[i].getFamilies();
			for(int j=0; j<fam.length; j++) {
				if(!fam[j].isAdjustable()) continue;
				Parameter[] pp = fam[j].getParameters();
				double[] val = fam[j].get();
				do {
					for(int k=0; k<pp.length; k++) {
						if(!pp[k].isAdjustable()) continue;
						pp[k].value = val[k] + pert*(random.nextDouble()-0.5);
					}
				} while(!fam[j].test());
			}

			ParamMemFunc[] mf = type[i].getParamMembershipFunctions();
			for(int j=0; j<mf.length; j++) {
				if(!mf[j].isAdjustable()) continue;
				Parameter[] pp = mf[j].getParameters();
				double[] val = mf[j].get();
				do {
					for(int k=0; k<pp.length; k++) {
						if(!pp[k].isAdjustable()) continue;
						pp[k].value = val[k] + pert*(random.nextDouble()-0.5);
					}
				} while(!mf[j].test());
			}
		}
	}
}

